package com.alogic.xscript.plugins;

import com.alogic.xscript.AbstractLogiclet;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateParser;
import org.apache.commons.lang3.time.DateUtils;

import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * 时间相关的插件
 * @since 1.6.13.6 [20200629 duanyy] <br>
 * - 增加Nano时间的获取； <br>
 */
public class Timestamp extends AbstractLogiclet {
    protected String $id;
    protected String pattern;
    protected String $value;

    public Timestamp(String tag, Logiclet p) {
        super(tag, p);
    }

    @Override
    public void configure(Properties p){
        super.configure(p);
        $id = PropertiesConstants.getRaw(p,"id","");
        $value = PropertiesConstants.getRaw(p,"value","");
        pattern = PropertiesConstants.getString(p,"pattern","",true);
    }

    @Override
    protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
        String id = PropertiesConstants.transform(ctx,$id,"");
        if (StringUtils.isNotEmpty(id)){
            long tt = PropertiesConstants.transform(ctx,$value,System.currentTimeMillis());
            if (StringUtils.isEmpty(pattern)){
                ctx.SetValue(id, String.valueOf(tt));
            }else{
                String value = DateFormatUtils.format(tt, pattern, Locale.US);
                ctx.SetValue(id, value);
            }
        }
    }

    public static class Parser extends AbstractLogiclet {
        protected String $id;
        protected String $pattern;
        protected String $value;

        public Parser(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p) {
            super.configure(p);
            $id = PropertiesConstants.getRaw(p, "id", "");
            $value = PropertiesConstants.getRaw(p, "value", "");
            $pattern = PropertiesConstants.getRaw(p, "pattern", "");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx, $id, "");
            if (StringUtils.isNotEmpty(id)) {
                String source = PropertiesConstants.transform(ctx, $value, "");
                try {
                    Date date = DateUtils.parseDate(source, PropertiesConstants.transform(ctx, $pattern, "yyyy-MM-dd HH:mm:ss"));
                    ctx.SetValue(id, String.valueOf(date.getTime()));
                } catch (Exception ex) {
                    ctx.SetValue(id, "false");
                }
            }
        }
    }

    /**
     * 毫秒级偏移
     */
    public static class Offset extends Timestamp {
        protected String $offset;
        public Offset(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                long tt = PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()) + PropertiesConstants.transform(ctx,$offset,0);
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(tt));
                }else{
                    String value = DateFormatUtils.format(tt, pattern, Locale.US);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 按月份偏移
     */
    public static class Month extends Timestamp {
        protected String $offset;
        public Month(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.MONTH,PropertiesConstants.transform(ctx,$offset,0));
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 按小时偏移
     */
    public static class Hour extends Timestamp {
        protected String $offset;
        public Hour(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.HOUR,PropertiesConstants.transform(ctx,$offset,0));
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 按小时偏移
     */
    public static class Day extends Timestamp {
        protected String $offset;
        public Day(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.DAY_OF_YEAR,PropertiesConstants.transform(ctx,$offset,0));
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 按星期偏移
     */
    public static class Week extends Timestamp {
        protected String $offset;
        public Week(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.WEEK_OF_YEAR,PropertiesConstants.transform(ctx,$offset,0));
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 按年偏移
     */
    public static class Year extends Timestamp {
        protected String $offset;
        public Year(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.YEAR,PropertiesConstants.transform(ctx,$offset,0));
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 本日的开始时间
     */
    public static class BeginOfDay extends Timestamp {
        protected String $offset;
        public BeginOfDay(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.DAY_OF_YEAR,PropertiesConstants.transform(ctx,$offset,0));
                calendar.set(Calendar.HOUR_OF_DAY,0);
                calendar.set(Calendar.MINUTE,0);
                calendar.set(Calendar.SECOND,0);
                calendar.set(Calendar.MILLISECOND,0);
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 本星期的开始时间
     */
    public static class BeginOfWeek extends Timestamp {
        protected String $offset;
        public BeginOfWeek(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.WEEK_OF_YEAR,PropertiesConstants.transform(ctx,$offset,0));
                calendar.set(Calendar.DAY_OF_WEEK,1);
                calendar.set(Calendar.HOUR_OF_DAY,0);
                calendar.set(Calendar.MINUTE,0);
                calendar.set(Calendar.SECOND,0);
                calendar.set(Calendar.MILLISECOND,0);
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 本星期的开始时间
     */
    public static class BeginOfMonth extends Timestamp {
        protected String $offset;
        public BeginOfMonth(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.MONTH,PropertiesConstants.transform(ctx,$offset,0));
                calendar.set(Calendar.DAY_OF_MONTH,1);
                calendar.set(Calendar.HOUR_OF_DAY,0);
                calendar.set(Calendar.MINUTE,0);
                calendar.set(Calendar.SECOND,0);
                calendar.set(Calendar.MILLISECOND,0);
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }

    /**
     * 本星期的开始时间
     */
    public static class BeginOfYear extends Timestamp {
        protected String $offset;
        public BeginOfYear(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            $offset = PropertiesConstants.getRaw(p,"offset","0");
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
            String id = PropertiesConstants.transform(ctx,$id,"");
            if (StringUtils.isNotEmpty(id)){
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(PropertiesConstants.transform(ctx,$value,System.currentTimeMillis()));
                calendar.add(Calendar.YEAR,PropertiesConstants.transform(ctx,$offset,0));
                calendar.set(Calendar.DAY_OF_YEAR,1);
                calendar.set(Calendar.HOUR_OF_DAY,0);
                calendar.set(Calendar.MINUTE,0);
                calendar.set(Calendar.SECOND,0);
                calendar.set(Calendar.MILLISECOND,0);
                if (StringUtils.isEmpty(pattern)){
                    ctx.SetValue(id, String.valueOf(calendar.getTimeInMillis()));
                }else{
                    String value = DateFormatUtils.format(calendar, pattern);
                    ctx.SetValue(id, value);
                }
            }
        }
    }
}
